<?
  // check if the content-type is what we excpect
  if("text/xml" != $CONTENT_TYPE)
  {
    print "Nothing special about the request ...";
    exit();
  }

  // main ..  
  header("Content-type: text/xml");
  
  // start building response ...  
  $sXmlResponse = "";
  $sXmlResponse .= "<?xml version=\"1.0\"?>";
  $sXmlResponse .= "<methodResponse>";
  $sXmlResponse .= "<params>";
  $sXmlResponse .= "<param>";
  $sXmlResponse .= "<value>";
    
  // read in raw post data and DOM parse it ...
  $fsHttpRawPostData = fopen("php://input", "rb");
  $oXml = domxml_open_mem(fgets($fsHttpRawPostData));
  fclose($fsHttpRawPostData);
  
  // go through request tree ...
  $oTemp = $oXml;
  if( !($oTemp &&
      (9 == $oTemp->node_type()) &&
      ($oTemp = $oTemp->document_element()) &&
      ("methodCall" == $oTemp->node_name()) &&
      (1 == $oTemp->node_type()) &&
      ($oTemp = $oTemp->child_nodes()) &&
      (2 == sizeof($oTemp))
      ))
  {
    // fault ...
    arpcFault(0, "Invalid request");
  }

  // intialize method name a parameter XML
  $sMethodName = NULL;
  $oXmlParams = NULL;
  
  // continue going through request tree ...    
  for($i = 0; $i < 2; $i++)
  {
    $oTemp1 = $oTemp[$i];
    if(!$oTemp1) break; // error ...
        
    if( ("methodName" == $oTemp1->node_name()) &&
        (1 == $oTemp1->node_type()) &&
        ($oTemp1 = $oTemp1->child_nodes()) &&
        (1 == sizeof($oTemp1)) &&
        ($oTemp1 = $oTemp1[0]) &&
        (3 == $oTemp1->node_type()) 
      )
    {
      // get method name ...
      $sMethodName = $oTemp1->node_value();
    }
    else if( ("params" == $oTemp1->node_name()) &&
             (1 == $oTemp1->node_type()) &&
             ($oTemp1 = $oTemp1->child_nodes()) &&
             (1 == sizeof($oTemp1)) &&
             ($oTemp1 = $oTemp1[0]) &&
             ("param" == $oTemp1->node_name()) &&
             (1 == $oTemp1->node_type()) &&
             ($oTemp1 = $oTemp1->child_nodes()) &&
             (1 == sizeof($oTemp1)) &&
             ($oTemp1 = $oTemp1[0]) &&
             ("value" == $oTemp1->node_name()) &&
             (1 == $oTemp1->node_type()) &&
             ($oTemp1 = $oTemp1->child_nodes()) &&
             (1 == sizeof($oTemp1)) &&
             ($oTemp1 = $oTemp1[0]) &&
             (1 == $oTemp1->node_type())
           )
    {
      // get parameter XML
      $oXmlParameter = $oTemp1;
    }
    else
    {
      // error ...
      break;
    }
  }
  
  if( (NULL == $sMethodName) || (NULL == $oXmlParameter) )
  {
    // fault ...
    arpcFault(0, "Invalid request");
  }

  // check if function exists ...      
  if(!function_exists("arpc" . $sMethodName))
  {
    // fault ...
    arpcFault(0, "Function doesn't exists");
  }
  
  // call function ...         
  $sXmlResponse .= call_user_func("arpc" . $sMethodName, $oXmlParameter);

  // complete response ...
  $sXmlResponse .= "</value>";
  $sXmlResponse .= "</param>";
  $sXmlResponse .= "</params>";
  $sXmlResponse .= "</methodResponse>";
  
  // send response ... 
  print $sXmlResponse;

  // done ...
  exit();

  function arpcFault($iFaultCode, $sFaultString)
  {
    // build fault string ...
    $sXmlFault = "";
    $sXmlFault .= "<?xml version=\"1.0\"?>";
    $sXmlFault .= "<methodResponse>";
    $sXmlFault .= "<fault>";
    $sXmlFault .= "<value>";
    $sXmlFault .= "<struct>";
    $sXmlFault .= "<member>";
    $sXmlFault .= "<name>faultCode</name>";
    $sXmlFault .= "<value><int>" . $iFaultCode . "</int></value>";
    $sXmlFault .= "</member>";
    $sXmlFault .= "<member>";
    $sXmlFault .= "<name>faultString</name>";
    $sXmlFault .= "<value><string>" . $sFaultString . "</string></value>";
    $sXmlFault .= "</member>";
    $sXmlFault .= "</struct>";
    $sXmlFault .= "</value>";
    $sXmlFault .= "</fault>";
    $sXmlFault .= "</methodResponse>";

    // send fault ...
    print $sXmlFault;
    
    // done ...
    exit();
  }

  function arpcExtractBasicType($oXml, $sDesiredBasicType)
  {
    $sValue = NULL;
    $oTemp = $oXml;
    
    if( $oTemp &&
        ($sDesiredBasicType == $oTemp->node_name()) &&
        (1 == $oTemp->node_type()) &&
        ($oTemp = $oTemp->child_nodes()) &&
        (1 == sizeof($oTemp)) &&
        ($oTemp = $oTemp[0]) &&
        (3 == $oTemp->node_name())
      )
    {
      $sValue = $oTemp->node_value();
    }
    
    return $sValue;
  }

  function arpcXmlToInt($oXml)
  {
    $iInt = NULL;
    
    if( ($sValue = arpcExtractBasicType($oXml, "int")) ||
        ($sValue = arpcExtractBasicType($oXml, "i4")) )
    {
      if(is_integer(iInt)) $iInt = $sValue;
    }
    
    return iInt;
  }
  
  function arpcXmlToBoolean($oXml)
  {
    $bBoolean = NULL;
    
    if($sValue = arpcExtractBasicType($oXml, "boolean"))
    {
      if("0" == $sValue)
      {
        $bBoolean = false;
      }
      else if("1" == $sValue)
      {
        $bBoolean = true;
      }
    }
    
    return $bBoolean;
  }
  
  function arpcXmlToString($oXml)
  {
    $sString = NULL;
    
    if($sString = arpcExtractBasicType($oXml, "string"))
    {
      $sString = str_replace("&lt;", "<", $sString);
      $sString = str_replace("&amp;", "&", $sString);
    }
    
    return $sString;
  }
  
  function arpcXmlToDouble($oXml)
  {
    $dDouble = NULL;
    
    if( ($sValue = arpcExtractBasicType($oXml, "double")) &&
        (is_double($sValue)) )
    {
      $sDouble = $sValue;
    }
        
    return $dDouble;
  }
  
  function arpcXmlToDate($oXml)
  {
    $oDate = NULL;
    
    if($sValue = arpcExtractBasicType($oXml, "dateTime.iso8601"))
    {
      $sValue = str_replace("T", " ", $sValue);
      $oDate = strtotime($sValue);
    }
    
    return $oDate;
  }
  
  class arpcNameValue
  {
    var $sName;
    var $oXmlValue;
    
    function arpcNameValue($sName, $oXmlValue)
    {
      $this->$sName = $sName;
      $this->$oXmlValue = $oXmlValue;
    }
  }
  
  function arpcXmlToStruct($oXml)
  {
    $aoNameValueArray = NULL;
    $oTemp = $oXml;
    
    if( $oTemp &&
        ("struct" == $oTemp->node_name()) &&
        (1 == $oTemp->node_type()) &&
        ($oTemp = $oTemp->child_nodes())
      )
    {
      $iNameValueArraySize = sizeof($oTemp);
      for($i = 0; $i < $iNameValueArraySize; $i++)
      {
        $oTemp1 = $oTemp[$i];
        if( $oTemp1 &&
            ("member" == $oTemp1->node_name()) &&
            (1 == $oTemp1->node_type()) &&
            ($oTemp1 = $oTemp1->child_nodes()) &&
            (2 == sizeof($oTemp1))
          )
        {
          $sName = NULL;
          $oXmlValue = NULL;
          
          for($j = 0; $j < 2; $j++)
          {
            $oTemp2 = $oTemp1[$j];
            if($oTemp2)
            {
              if( ("name" == $oTemp2->node_name()) &&
                  (1 == $oTemp2->node_type()) &&
                  ($oTemp2 = $oTemp2->child_nodes()) &&
                  (1 == sizeof($oTemp2)) &&
                  ($oTemp2 = $oTemp[0]) &&
                  (3 == $oTemp2->node_type())
                )
              {
                $sName = $oTemp2->node_value();
              }
              else if( ("value" == $oTemp2->node_name()) &&
                        (1 == $oTemp2->node_type()) &&
                        ($oTemp2 = $oTemp2->child_nodes()) &&
                        (1 == sizeof($oTemp2)) &&
                        ($oTemp2 = $oTemp2[0]) &&
                        (1 == $oTemp2->node_type())
                      )
              {
                $oXmlValue = $oTemp2;
              }
              else
              {
                return NULL;
              }
            }
            else
            {
              return NULL;
            }
          }
        
          if( (NULL != $sName) && (NULL != $oXmlValue) )
          {
            $aoNameValueArray[$i] = new arpcNameValue($sName, $oXmlValue);
          }
          else
          {
            return NULL;
          }
        }
        else
        {
        return NULL;
        }
      }
    }
    
    return $aoNameValueArray;
  }
  
  function arpcXmlToArray($oXml, $funcXmlTo)
  {
    $aArray = NULL;
    $oTemp = $oXml;
    
    if( $oTemp &&
        ("array" == $oTemp->node_name()) &&
        (1 == $oTemp->node_type()) &&
        ($oTemp = $oTemp->child_nodes()) &&
        (1 == sizeof($oTemp)) &&
        ($oTemp = $oTemp[0]) &&
        ("data" == $oTemp->node_name()) &&
        (1 == $oTemp->node_type()) &&
        ($oTemp = $oTemp->child_nodes())
      )
    {
      $iArraySize = sizeof($oTemp);
      for($i = 0; $i < $iArraySize; $i++)
      {
        $iTemp1 = $iTemp[$i];
        if( $oTemp1 &&
            ("value" == $oTemp1->node_name()) &&
            (1 == $oTemp1->node_type()) &&
            ($oTemp1 = $oTemp1->child_nodes()) &&
            (1 == sizeof($oTemp1)) &&
            ($oTemp1 = $oTemp1[0]) &&
            (NULL != ($temp = $funcXmlTo($oTemp1)))
          )
        {
          $aArray[$i] = $temp;
        }
        else
        {
          return NULL;
        }
      }
    }
    
    return $aArray;
  }
  
  function arpcIntToXml($iInteger)
  {
    return ("<int>" . $iInteger . "</int>");
  }
  
  function arpcBooleanToXml($bBoolean)
  {
    return("<boolean>" . ($bBoolean ? "1" : "0") . "</boolean>");
  }
  
  function arpcStringToXml($sString)
  {
    $sString = str_replace("&", "&amp;", $sString);
    $sString = str_replace("<", "&lt;", $sString);
    return ("<string>" . $sString . "</string>");
  }
  
  function arpcDoubleToXml($dDouble)
  {
    return ("<double>" . $dDouble . "</double>");
  }
  
  function arpcDateToXml($oDate)
  {
    $sDate = date("c", $oDate);
    return ("<dateTime.iso8601>" . $sDate . "</dateTime.iso8601>");
  }
  
  function arpcArrayToXml($aArray, $funcToXml)
  {
    $sXml = "";
    
    $sXml .= "<array>";
    $sXml .= "<data>";
    
    for($i = 0; $i < sizeof($aArray); $i++)
    {
      $sXml .= "<value>" . $funcToXml($aArray[$i]) . "</value>";
    }
    
    $sXml .= "</data>";
    $sXml .= "</array>";
    
    return $sXml;
  }
?>